# -*- coding: utf-8 -*-
# @Time    : 2024/7/5 11:46
# @Author  : yujiahao
# @File    : 05_fastapi_request_body.py
# @description:请求体

'''
【请求体】
    - FastAPI 使用请求体从客户端（例如浏览器）向 API 发送数据。
    - 请求体是客户端发送给 API 的数据。响应体是 API 发送给客户端的数据。
    - API 基本上肯定要发送响应体，但是客户端不一定发送请求体。
    - 使用 Pydantic 模型声明请求体，能充分利用它的功能和优点。
【说明】
    - 发送数据使用 POST（最常用）、PUT、DELETE、PATCH 等操作。
    - 规范中没有定义使用 GET 发送请求体的操作，但不管怎样，FastAPI 也支持这种方式，只不过仅用于非常复杂或极端的用例。
    - 不建议使用 GET，因此，在 Swagger UI 交互文档中不会显示有关 GET 的内容，而且代理协议也不一定支持 GET。
'''

from fastapi import FastAPI
from pydantic import BaseModel


class Item(BaseModel):
    '''
    - 创建数据模型 把数据模型声明为继承 BaseModel 的类。
    - BaseModel 是 FastAPI 和 Pydantic 中的一个核心类，用于定义数据模型。
    - 它提供了数据验证和解析的功能，可以轻松地处理请求体、响应体、路径参数、查询参数等。
    - 与声明查询参数一样，包含默认值的模型属性是可选的，否则就是必选的。默认值为 None 的模型属性也是可选的。
    - 模型声明如下 JSON 对象（即 Python 字典）：

        {
            "name": "Foo",
            "description": "An optional description",
            "price": 45.2,
            "tax": 3.5
        }
    '''
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


app = FastAPI()


# todo 1、请求体
# 与声明查询参数一样，包含默认值的模型属性是可选的，否则就是必选的。默认值为 None 的模型属性也是可选的。
@app.post("/items/")
async def create_item(item: Item):
    '''
     Item 模型将自动验证传入的 JSON 数据，确保传进来的数值符合数据类型要求
    【结论】
    仅使用 Python 类型声明，FastAPI 就可以：
        - 以 JSON 形式读取请求体
        -（在必要时）把请求体转换为对应的类型
        - 校验数据：
            - 数据无效时返回错误信息，并指出错误数据的确切位置和内容
        - 把接收的数据赋值给参数 item
            - 把函数中请求体参数的类型声明为 Item，还能获得代码补全等编辑器支持
        - 为模型生成 JSON Schema，在项目中所需的位置使用
        - 这些概图是 OpenAPI 概图的部件，用于 API 文档 UI
    '''

    item_dict = item.dict()
    if item.tax:
        price_with_tax = item.price + item.tax
        item_dict.update({"price_with_tax": price_with_tax})
    return item_dict


# todo 2、请求体+路径参数

@app.put('/item/{item_id}')
async def update_item(item_id: int, item: Item):
    # **item.dict()是一个解包的操作,用**可以将pydantic模型实例转换为字典
    return {"item_id": item_id, **item.dict()}


# todo 3、请求体 + 路径参数 + 查询参数
@app.put("/items/{item_id}")
async def update_items(item_id: int, item: Item, q: str | None = None):
    '''
    FastAPI 支持同时声明请求体、路径参数和查询参数。
    FastAPI 能够正确识别这三种参数，并从正确的位置获取数据。
    函数参数按如下规则进行识别：
    - 路径中声明了相同参数的参数，是路径参数
    - 类型是（int、float、str、bool 等）单类型的参数，是查询参数
    - 类型是 Pydantic 模型的参数，是请求体
    笔记
    - 因为默认值是 None， FastAPI 会把 q 当作可选参数。
    - FastAPI 不使用 Optional[str] 中的 Optional， 但 Optional 可以让编辑器提供更好的支持，并检测错误。
    '''

    result = {"item_id": item_id, **item.dict()}
    if q:
        result.update({"q": q})
    return result
